﻿using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Text;
using System.Threading;
using Ben.Http;

namespace Red
{
    public class ClockImageBuilder : IRequestHandler
    {
        private readonly byte[] _header = Encoding.UTF8.GetBytes(@"HTTP/1.0 200 OK
Content-Type: multipart/x-mixed-replace; boundary=2CC4C358-90C3-4472-9882-6A8B25EF4CA4

--2CC4C358-90C3-4472-9882-6A8B25EF4CA4
");
        private readonly byte[] _imageHeader = Encoding.UTF8.GetBytes(@"Content-Type: image/jpeg

");
        private readonly byte[] _imageFooter = Encoding.UTF8.GetBytes(@"
--2CC4C358-90C3-4472-9882-6A8B25EF4CA4
");
        private readonly byte[] _error = Encoding.UTF8.GetBytes(@"HTTP/1.0 404 Not Found
Content-Length: 0
Content-Type: text/html

");

        private readonly object _syncRoot = new object();
        private readonly List<object> _keepRunning;
        private readonly List<object> _isRunning;
        private readonly List<ClientRequest> _clients;

        public bool CanHandle(ClientRequest request) { return true; }
        public bool IsRunning { get { return _isRunning.Count > 0; } }

        public Color ForeColor { get; set; }
        public Color BackColor { get; set; }

        public ClockImageBuilder()
        {
            ForeColor = Color.Red;
            BackColor = Color.Black;
            _keepRunning = new List<object>();
            _isRunning = new List<object>();
            _clients = new List<ClientRequest>();
        }

        public void Process(ClientRequest request)
        {
            request.Client.Blocking = true;
            request.Client.Send(_header);
            lock (_syncRoot)
            {
                _clients.Add(request);
            }
        }

        public void Start()
        {
            if (IsRunning) return;
            new Thread(Execute) {IsBackground = true}.Start();
        }

        private void Execute()
        {
            const double fps = 20.0;
            _isRunning.Add(1);
            _keepRunning.Add(1);

            var rect = new Rectangle(0, 0, 140, 30);
            var bmp = new Bitmap(140, 30);
            var font = new Font("Arial", 16);
            var brush = new SolidBrush(ForeColor);
            var g = Graphics.FromImage(bmp);
            var mem = new MemoryStream();
            try
            {
                while (_keepRunning.Count > 0)
                {
                    var nextTime = DateTime.Now.AddMilliseconds(1000.0 / fps);
                    g.Clear(BackColor);
                    g.DrawString(DateTime.Now.ToString("HH:mm:ss.fff"), font, brush, rect);
                    mem.SetLength(0);
                    bmp.Save(mem, ImageFormat.Jpeg);
                    var buffer = mem.ToArray();
                    lock (_syncRoot)
                    {
                        foreach (var c in _clients.ToArray())
                        {
                            try
                            {
                                c.Client.Send(_imageHeader);
                                c.Client.Send(buffer);
                                c.Client.Send(_imageFooter);
                            }
                            catch (Exception ex)
                            {
                                Console.WriteLine(ex.Message);
                                _clients.Remove(c);
                            }
                        }
                    }
                    var sleep = nextTime.Subtract(DateTime.Now);
                    if (sleep <= TimeSpan.Zero) continue;
                    Thread.Sleep(sleep);
                }
            }
            finally
            {
                brush.Dispose();
                font.Dispose();
                mem.Dispose();
                g.Dispose();
                bmp.Dispose();
            }
            _isRunning.Clear();
        }

        public void Stop()
        {
            _keepRunning.Clear();
        }
    }
}
